#pragma once

#include "Matrix.hpp"
namespace zzz{
template <typename T>
class Matrix<2, 2, T> : public MatrixBase<2, 2, T>
{
public:
  Matrix(){}
  Matrix(const Matrix<2, 2, T> &mat):MatrixBase<2, 2, T>(mat){}
  Matrix(const MatrixBase<2, 2, T> &mat):MatrixBase<2, 2, T>(mat){}
  template<typename T1> explicit Matrix<2, 2, T>(const MatrixBase<2, 2,T1>& a):MatrixBase<2, 2, T>(a) {}
  template<typename T1> explicit Matrix<2, 2, T>(const Matrix<2, 2,T1>& a):MatrixBase<2, 2, T>(a) {}
  template<typename T1> explicit Matrix<2, 2, T>(const T1 *p):MatrixBase<2, 2, T>(p) {}
  Matrix(const T& a,const T& b,const T& c,const T& d)
  {
    T* v=Data();
    v[0]=a; v[1]=b;
    v[2]=c; v[3]=d;
  }
  explicit Matrix(const T *p)
  {
    T* v=Data();
    v[0]=p[0];  v[1]=p[1];  
    v[2]=p[2];  v[3]=p[3];
  }
  Matrix(const Vector<2, T>& a,const Vector<2, T>& b)
  {
    T* v=Data();
    v[0]=a[0]; v[1]=a[1];
    v[2]=b[0]; v[3]=b[1];
  }
  explicit Matrix(const Vector<2, T> *a)
  {
    T* v=Data();
    v[0]=a[0][0]; v[1]=a[0][1];
    v[2]=a[1][0]; v[3]=a[1][1];
  }

  //assign
  inline const Matrix<2, 2, T> &operator=(const Matrix<2, 2, T>& a){MatrixBase<2, 2, T>::operator =(a); return *this;}
  using MatrixBase<2, 2, T>::operator=;
  using MatrixBase<2, 2, T>::Data;

  //alias
  const T& m00() const {return Data()[0];}
  const T& m01() const {return Data()[1];}
  const T& m10() const {return Data()[2];}
  const T& m11() const {return Data()[3];}
  const T& v0() const {return Data()[0];}
  const T& v1() const {return Data()[1];}
  const T& v2() const {return Data()[2];}
  const T& v3() const {return Data()[3];}
  T& m00() {return Data()[0];}
  T& m01() {return Data()[1];}
  T& m10() {return Data()[2];}
  T& m11() {return Data()[3];}
  T& v0() {return Data()[0];}
  T& v1() {return Data()[1];}
  T& v2() {return Data()[2];}
  T& v3() {return Data()[3];}

  //operator
  using MatrixBase<2, 2, T>::operator *;
};

typedef Matrix<2, 2,zint8> Matrix2x2i8;
typedef Matrix<2, 2,zuint8> Matrix2x2ui8;
typedef Matrix<2, 2,zint16> Matrix2x2i16;
typedef Matrix<2, 2,zuint16> Matrix2x2ui16;
typedef Matrix<2, 2,zint32> Matrix2x2i32;
typedef Matrix<2, 2,zuint32> Matrix2x2ui32;
typedef Matrix<2, 2,zint64> Matrix2x2i64;
typedef Matrix<2, 2,zuint64> Matrix2x2ui64;
typedef Matrix<2, 2,zfloat32> Matrix2x2f32;
typedef Matrix<2, 2,zfloat64> Matrix2x2f64;

typedef Matrix<2, 2,zuint> Matrix2x2ui;
typedef Matrix<2, 2,int> Matrix2x2i;
typedef Matrix<2, 2,float> Matrix2x2f;
typedef Matrix<2, 2,double> Matrix2x2d;
}
